using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Collections;
using System.Text.RegularExpressions;

namespace [%NAMESPACE%]
{
    public class MultiLookup : ContainerBase, IEnumerable<Lookup>
    {
        #region Constructor
        public MultiLookup(ItemBase p_parentItem, string p_fieldName, Guid p_lookupWebGuid, Guid p_lookupListGuid, string p_lookupField, bool p_emptyAllowed)
            : base(p_parentItem, p_fieldName, p_emptyAllowed)
        {
            if (p_parentItem == null) throw new PointBridgeEx("MultiLookup constructor: p_parentItem is null.");
            if (p_fieldName == null) throw new PointBridgeEx("MultiLookup constructor: p_fieldName is null.");
            if (p_lookupField == null) throw new PointBridgeEx("MultiLookup constructor: p_lookupField is null.");

            lookupWebGuid = p_lookupWebGuid;
            lookupListGuid = p_lookupListGuid;
            lookupField = p_lookupField;
        }
        public MultiLookup(ItemBase p_parentItem, string p_fieldName, SPFieldLookup p_lookupColumn, bool p_emptyAllowed)
            : base(p_parentItem, p_fieldName, p_emptyAllowed)
        {
            if (p_parentItem == null) throw new PointBridgeEx("MultiLookup constructor: p_parentItem is null.");
            if (p_fieldName == null) throw new PointBridgeEx("MultiLookup constructor: p_fieldName is null.");

            lookupWebGuid = p_lookupColumn.LookupWebId;
            if (Lookup.IsGuid(p_lookupColumn.LookupList) != true) throw new PointBridgeEx("UNexpected error: lookupColumn.LookupList is not GUID, it is '" + p_lookupColumn.LookupList + "'");
            lookupListGuid = new Guid(p_lookupColumn.LookupList);
            if (p_lookupColumn.LookupField != null) lookupField = p_lookupColumn.LookupField;
            else lookupField = "Title";
        }
        #endregion

        #region Methods
        public virtual Lookup this[int key]
        {
            get { return _arr[key]; }
        }
        public virtual int Count
        {
            get { return _arr.Count; }
        }
        public override void SetEmpty()
        {
            _arr.Clear();
            ForceUpdate();
        }
        public virtual void AddSelection(int newValueId)
        {
            //check if alredy selected
            foreach (Lookup option in this)
            {
                if (option.valueId == newValueId) return;
            }

            Lookup item = new Lookup(this, newValueId);
            _arr.Add(item);
            ForceUpdate();
        }
        public virtual void RemoveSelection(int valueIdToRemove)
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                if (_arr[i].valueId == valueIdToRemove)
                {
                    _arr.RemoveAt(i);
                    ForceUpdate();
                    return;
                }
            }
            throw new PointBridgeEx("Lookup.RemoveLookupSelection(): unable to find valueIdToRemove = " + valueIdToRemove);
        }
        public virtual Lookup FindSelection(int valueId)
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                if (_arr[i].valueId == valueId) return _arr[i];
            }
            return null;
        }
        public virtual bool ContainsSelection(int valueId)
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                if (_arr[i].valueId == valueId) return true;
            }
            return false;
        }
        public string GetSemicolonSeparatedString()
        {
            StringBuilder str = new StringBuilder();
            bool first = true;
            foreach (Lookup option in this)
            {
                if (first == true) first = false;
                else str.Append("; ");
                str.Append(option.valueString);
            }
            return str.ToString();
        }
        public SPListItem GetReferencedItem(int p_valueId)
        {
            return Lookup.GetReferencedItem(site, lookupWebGuid, lookupListGuid, p_valueId);
        }
        public override string ToString()
        {
            if (isEmpty == true) return "<Empty>";
            else return GetSemicolonSeparatedString();
        }

        public override void ForceUpdate()
        {
            parentItem.item[fieldName] = ToSPRepresentation();
        }
        public override object ToSPRepresentation()
        {
            if (_arr.Count == 0)
            {
                if (emptyAllowed == true) return null;
                else throw new PointBridgeEx("MiltiLookup.ToSPRepresentation(): count is 0 while emptyAllowed is false");
            }

            Dictionary<int, bool> valueIds = new Dictionary<int, bool>();
            SPFieldLookupValueCollection options = new SPFieldLookupValueCollection();
            foreach (Lookup option in this)
            {
                if (option.isEmpty == true) throw new PointBridgeEx("MultiLookup.ToSPRepresentation(): Lookup is empty. This should never happen.");
                if (valueIds.ContainsKey((int)option.valueId)) throw new PointBridgeEx("MultiLookup.ToSPRepresentation(): Multi-Lookup contains a duplicate valueId = " + (int)option.valueId);
                valueIds.Add((int)option.valueId, true);
                options.Add(new SPFieldLookupValue((int)option.valueId, option.valueString));
            }
            return options;
        }
        public override void InitFromSPRepresentation(object obj)
        {
            _arr.Clear();
            if (obj == null)
            {
                if (emptyAllowed == true) return;
                else throw new PointBridgeEx("MultiLookup.InitFromSPRepresentation(): object is not initialized while emptyAllowed is false");
            }

            //multi lookup could come as a string or as an SPFieldLookupValueCollection
            //Format: "1;#Title;#2;#Title2"
            if (obj.GetType() == typeof(string))
            {
                string str = (string)obj;
                string[] separators = new string[1];
                separators[0] = ";#";
                string[] splits = str.Trim().Split(separators, StringSplitOptions.None);
                try
                {
                    for (int i = 0; i < splits.Length; i = i + 2)
                    {
                        int valueId = int.Parse(splits[i]);
                        string valueString = splits[i + 1];
                        Lookup option = new Lookup(this, valueId, valueString);
                        _arr.Add(option);
                    }
                }
                catch (Exception ex)
                {
                    throw new PointBridgeEx(string.Format("MultiLookup.InitFromSPRepresentation(): SP representation string ({0} is in an incorrect format: {1})", str, ex.Message));
                }
            }
            else
            {
                SPFieldLookupValueCollection options = (SPFieldLookupValueCollection)obj;
                foreach (SPFieldLookupValue rawValue in options)
                {
                    Lookup option = new Lookup(this, rawValue.LookupId, rawValue.LookupValue);
                    _arr.Add(option);
                }
            }
        }
        public static int GetCountFromSPRepresentation(object obj)
        {
            if (obj == null) return 0;

            //multi lookup could come as a string or as an SPFieldLookupValueCollection
            //Format: "1;#Title;#2;#Title2"
            if (obj.GetType() == typeof(string))
            {
                string str = (string)obj;
                string[] separators = new string[1];
                separators[0] = ";#";
                string[] splits = str.Trim().Split(separators, StringSplitOptions.None);
                if (splits.Length % 2 != 0) throw new PointBridgeEx(string.Format("MultiLookup.GetCountFromSPRepresentation(): SP representation string ({0} is in an incorrect format", str));
                return (int)splits.Length / 2;
            }
            else
            {
                SPFieldLookupValueCollection options = (SPFieldLookupValueCollection)obj;
                return options.Count;
            }
        }
        #endregion

        #region Public Properties
        public SPSite site
        {
            get
            {
                return web.Site;
            }
        }
        public SPWeb web
        {
            get
            {
                return parentItem.item.Web;
            }
        }
        public override bool isEmpty
        {
            get
            {
                if (_arr.Count == 0) return true;
                else return false;
            }
        }

        public readonly Guid lookupWebGuid;
        public readonly Guid lookupListGuid;
        public readonly string lookupField;
        #endregion

        #region IEnumerable implementation
        public IEnumerator<Lookup> GetEnumerator()
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                yield return _arr[i];
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Internal fields
        protected List<Lookup> _arr = new List<Lookup>();
        #endregion
    }
}
